home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / jpeg / jcmain.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  21KB  |  693 lines

  1. /*
  2.  * jcmain.c
  3.  *
  4.  * Copyright (C) 1991, 1992, Thomas G. Lane.
  5.  * This file is part of the Independent JPEG Group's software.
  6.  * For conditions of distribution and use, see the accompanying README file.
  7.  *
  8.  * This file contains a command-line user interface for the JPEG compressor.
  9.  * It should work on any system with Unix- or MS-DOS-style command lines.
  10.  *
  11.  * Two different command line styles are permitted, depending on the
  12.  * compile-time switch TWO_FILE_COMMANDLINE:
  13.  *    cjpeg [options]  inputfile outputfile
  14.  *    cjpeg [options]  [inputfile]
  15.  * In the second style, output is always to standard output, which you'd
  16.  * normally redirect to a file or pipe to some other program.  Input is
  17.  * either from a named file or from standard input (typically redirected).
  18.  * The second style is convenient on Unix but is unhelpful on systems that
  19.  * don't support pipes.  Also, you MUST use the first style if your system
  20.  * doesn't do binary I/O to stdin/stdout.
  21.  */
  22.  
  23. #include "jinclude.h"
  24. #ifdef INCLUDES_ARE_ANSI
  25. #include <stdlib.h>        /* to declare exit() */
  26. #endif
  27. #include <ctype.h>        /* to declare isupper(), tolower() */
  28. #ifdef NEED_SIGNAL_CATCHER
  29. #include <signal.h>        /* to declare signal() */
  30. #endif
  31. #ifdef USE_SETMODE
  32. #include <fcntl.h>        /* to declare setmode() */
  33. #endif
  34.  
  35. #ifdef THINK_C
  36. #include <console.h>        /* command-line reader for Macintosh */
  37. #endif
  38.  
  39. #ifdef DONT_USE_B_MODE        /* define mode parameters for fopen() */
  40. #define READ_BINARY    "r"
  41. #define WRITE_BINARY    "w"
  42. #else
  43. #define READ_BINARY    "rb"
  44. #define WRITE_BINARY    "wb"
  45. #endif
  46.  
  47. #ifndef EXIT_FAILURE        /* define exit() codes if not provided */
  48. #define EXIT_FAILURE  1
  49. #endif
  50. #ifndef EXIT_SUCCESS
  51. #ifdef VMS
  52. #define EXIT_SUCCESS  1        /* VMS is very nonstandard */
  53. #else
  54. #define EXIT_SUCCESS  0
  55. #endif
  56. #endif
  57.  
  58.  
  59. #include "jversion.h"        /* for version message */
  60.  
  61.  
  62. /*
  63.  * This routine determines what format the input file is,
  64.  * and selects the appropriate input-reading module.
  65.  *
  66.  * To determine which family of input formats the file belongs to,
  67.  * we may look only at the first byte of the file, since C does not
  68.  * guarantee that more than one character can be pushed back with ungetc.
  69.  * Looking at additional bytes would require one of these approaches:
  70.  *     1) assume we can fseek() the input file (fails for piped input);
  71.  *     2) assume we can push back more than one character (works in
  72.  *        some C implementations, but unportable);
  73.  *     3) provide our own buffering as is done in djpeg (breaks input readers
  74.  *        that want to use stdio directly, such as the RLE library);
  75.  * or  4) don't put back the data, and modify the input_init methods to assume
  76.  *        they start reading after the start of file (also breaks RLE library).
  77.  * #1 is attractive for MS-DOS but is untenable on Unix.
  78.  *
  79.  * The most portable solution for file types that can't be identified by their
  80.  * first byte is to make the user tell us what they are.  This is also the
  81.  * only approach for "raw" file types that contain only arbitrary values.
  82.  * We presently apply this method for Targa files.  Most of the time Targa
  83.  * files start with 0x00, so we recognize that case.  Potentially, however,
  84.  * a Targa file could start with any byte value (byte 0 is the length of the
  85.  * seldom-used ID field), so we provide a switch to force Targa input mode.
  86.  */
  87.  
  88. static boolean is_targa;    /* records user -targa switch */
  89.  
  90.  
  91. LOCAL void
  92. select_file_type (compress_info_ptr cinfo)
  93. {
  94.   int c;
  95.  
  96.   if (is_targa) {
  97. #ifdef TARGA_SUPPORTED
  98.     jselrtarga(cinfo);
  99. #else
  100.     ERREXIT(cinfo->emethods, "Targa support was not compiled");
  101. #endif
  102.     return;
  103.   }
  104.  
  105.   if ((c = getc(cinfo->input_file)) == EOF)
  106.     ERREXIT(cinfo->emethods, "Empty input file");
  107.  
  108.   switch (c) {
  109. #ifdef GIF_SUPPORTED
  110.   case 'G':
  111.     jselrgif(cinfo);
  112.     break;
  113. #endif
  114. #ifdef PPM_SUPPORTED
  115.   case 'P':
  116.     jselrppm(cinfo);
  117.     break;
  118. #endif
  119. #ifdef RLE_SUPPORTED
  120.   case 'R':
  121.     jselrrle(cinfo);
  122.     break;
  123. #endif
  124. #ifdef TARGA_SUPPORTED
  125.   case 0x00:
  126.     jselrtarga(cinfo);
  127.     break;
  128. #endif
  129.   default:
  130. #ifdef TARGA_SUPPORTED
  131.     ERREXIT(cinfo->emethods, "Unrecognized input file format --- perhaps you need -targa");
  132. #else
  133.     ERREXIT(cinfo->emethods, "Unrecognized input file format");
  134. #endif
  135.     break;
  136.   }
  137.  
  138.   if (ungetc(c, cinfo->input_file) == EOF)
  139.     ERREXIT(cinfo->emethods, "ungetc failed");
  140. }
  141.  
  142.  
  143. /*
  144.  * This routine gets control after the input file header has been read.
  145.  * It must determine what output JPEG file format is to be written,
  146.  * and make any other compression parameter changes that are desirable.
  147.  */
  148.  
  149. METHODDEF void
  150. c_ui_method_selection (compress_info_ptr cinfo)
  151. {
  152.   /* If the input is gray scale, generate a monochrome JPEG file. */
  153.   if (cinfo->in_color_space == CS_GRAYSCALE)
  154.     j_monochrome_default(cinfo);
  155.   /* For now, always select JFIF output format. */
  156. #ifdef JFIF_SUPPORTED
  157.   jselwjfif(cinfo);
  158. #else
  159.   You shoulda defined JFIF_SUPPORTED.   /* deliberate syntax error */
  160. #endif
  161. }
  162.  
  163.  
  164. /*
  165.  * Signal catcher to ensure that temporary files are removed before aborting.
  166.  * NB: for Amiga Manx C this is actually a global routine named _abort();
  167.  * see -Dsignal_catcher=_abort in CFLAGS.  Talk about bogus...
  168.  */
  169.  
  170. #ifdef NEED_SIGNAL_CATCHER
  171.  
  172. static external_methods_ptr emethods; /* for access to free_all */
  173.  
  174. GLOBAL void
  175. signal_catcher (int signum)
  176. {
  177.   if (emethods != NULL) {
  178.     emethods->trace_level = 0;    /* turn off trace output */
  179.     (*emethods->free_all) ();    /* clean up memory allocation & temp files */
  180.   }
  181.   exit(EXIT_FAILURE);
  182. }
  183.  
  184. #endif
  185.  
  186.  
  187. /*
  188.  * Optional routine to display a percent-done figure on stderr.
  189.  * See jcdeflts.c for explanation of the information used.
  190.  */
  191.  
  192. #ifdef PROGRESS_REPORT
  193.  
  194. METHODDEF void
  195. progress_monitor (compress_info_ptr cinfo, long loopcounter, long looplimit)
  196. {
  197.   if (cinfo->total_passes > 1) {
  198.     fprintf(stderr, "\rPass %d/%d: %3d%% ",
  199.         cinfo->completed_passes+1, cinfo->total_passes,
  200.         (int) (loopcounter*100L/looplimit));
  201.   } else {
  202.     fprintf(stderr, "\r %3d%% ",
  203.         (int) (loopcounter*100L/looplimit));
  204.   }
  205.   fflush(stderr);
  206. }
  207.  
  208. #endif
  209.  
  210.  
  211. /*
  212.  * Argument-parsing code.
  213.  * The switch parser is designed to be useful with DOS-style command line
  214.  * syntax, ie, intermixed switches and file names, where only the switches
  215.  * to the left of a given file name affect processing of that file.
  216.  * The main program in this file doesn't actually use this capability...
  217.  */
  218.  
  219.  
  220. static char * progname;        /* program name for error messages */
  221.  
  222.  
  223. LOCAL void
  224. usage (void)
  225. /* complain about bad command line */
  226. {
  227.   fprintf(stderr, "usage: %s [switches] ", progname);
  228. #ifdef TWO_FILE_COMMANDLINE
  229.   fprintf(stderr, "inputfile outputfile\n");
  230. #else
  231.   fprintf(stderr, "[inputfile]\n");
  232. #endif
  233.  
  234.   fprintf(stderr, "Switches (names may be abbreviated):\n");
  235.   fprintf(stderr, "  -quality N     Compression quality (0..100; 5-95 is useful range)\n");
  236.   fprintf(stderr, "  -grayscale     Create monochrome JPEG file\n");
  237. #ifdef ENTROPY_OPT_SUPPORTED
  238.   fprintf(stderr, "  -optimize      Optimize Huffman table (smaller file, but slow compression)\n");
  239. #endif
  240. #ifdef TARGA_SUPPORTED
  241.   fprintf(stderr, "  -targa         Input file is Targa format (usually not needed)\n");
  242. #endif
  243.   fprintf(stderr, "Switches for advanced users:\n");
  244.   fprintf(stderr, "  -restart N     Set restart interval in rows, or in blocks with B\n");
  245. #ifdef INPUT_SMOOTHING_SUPPORTED
  246.   fprintf(stderr, "  -smooth N      Smooth dithered input (N=1..100 is strength)\n");
  247. #endif
  248.   fprintf(stderr, "  -maxmemory N   Maximum memory to use (in kbytes)\n");
  249.   fprintf(stderr, "  -verbose  or  -debug   Emit debug output\n");
  250.   fprintf(stderr, "Switches for wizards:\n");
  251. #ifdef C_ARITH_CODING_SUPPORTED
  252.   fprintf(stderr, "  -arithmetic    Use arithmetic coding\n");
  253. #endif
  254. #ifdef C_MULTISCAN_FILES_SUPPORTED
  255.   fprintf(stderr, "  -nointerleave  Create noninterleaved JPEG file\n");
  256. #endif
  257.   fprintf(stderr, "  -qtables file  Use quantization tables given in file\n");
  258.   fprintf(stderr, "  -sample HxV[,...]  Set JPEG sampling factors\n");
  259.   exit(EXIT_FAILURE);
  260. }
  261.  
  262.  
  263. LOCAL boolean
  264. keymatch (char * arg, const char * keyword, int minchars)
  265. /* Case-insensitive matching of (possibly abbreviated) keyword switches. */
  266. /* keyword is the constant keyword (must be lower case already), */
  267. /* minchars is length of minimum legal abbreviation. */
  268. {
  269.   register int ca, ck;
  270.   register int nmatched = 0;
  271.  
  272.   while ((ca = *arg++) != '\0') {
  273.     if ((ck = *keyword++) == '\0')
  274.       return FALSE;        /* arg longer than keyword, no good */
  275.     if (isupper(ca))        /* force arg to lcase (assume ck is already) */
  276.       ca = tolower(ca);
  277.     if (ca != ck)
  278.       return FALSE;        /* no good */
  279.     nmatched++;            /* count matched characters */
  280.   }
  281.   /* reached end of argument; fail if it's too short for unique abbrev */
  282.   if (nmatched < minchars)
  283.     return FALSE;
  284.   return TRUE;            /* A-OK */
  285. }
  286.  
  287.  
  288. LOCAL int
  289. qt_getc (FILE * file)
  290. /* Read next char, skipping over any comments (# to end of line) */
  291. /* A comment/newline sequence is returned as a newline */
  292. {
  293.   register int ch;
  294.   
  295.   ch = getc(file);
  296.   if (ch == '#') {
  297.     do {
  298.       ch = getc(file);
  299.     } while (ch != '\n' && ch != EOF);
  300.   }
  301.   return ch;
  302. }
  303.  
  304.  
  305. LOCAL long
  306. read_qt_integer (FILE * file)
  307. /* Read an unsigned decimal integer from a quantization-table file */
  308. /* Swallows one trailing character after the integer */
  309. {
  310.   register int ch;
  311.   register long val;
  312.   
  313.   /* Skip any leading whitespace, detect EOF */
  314.   do {
  315.     ch = qt_getc(file);
  316.     if (ch == EOF)
  317.       return EOF;
  318.   } while (isspace(ch));
  319.   
  320.   if (! isdigit(ch)) {
  321.     fprintf(stderr, "%s: bogus data in quantization file\n", progname);
  322.     exit(EXIT_FAILURE);
  323.   }
  324.  
  325.   val = ch - '0';
  326.   while (ch = qt_getc(file), isdigit(ch)) {
  327.     val *= 10;
  328.     val += ch - '0';
  329.   }
  330.   return val;
  331. }
  332.  
  333.  
  334. LOCAL void
  335. read_quant_tables (compress_info_ptr cinfo, char * filename, int scale_factor)
  336. /* Read a set of quantization tables from the specified file.
  337.  * The file is plain ASCII text: decimal numbers with whitespace between.
  338.  * Comments preceded by '#' may be included in the file.
  339.  * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values.
  340.  * The tables are implicitly numbered 0,1,etc.
  341.  */
  342. {
  343.   /* ZIG[i] is the zigzag-order position of the i'th element of a DCT block */
  344.   /* read in natural order (left to right, top to bottom). */
  345.   static const short ZIG[DCTSIZE2] = {
  346.      0,  1,  5,  6, 14, 15, 27, 28,
  347.      2,  4,  7, 13, 16, 26, 29, 42,
  348.      3,  8, 12, 17, 25, 30, 41, 43,
  349.      9, 11, 18, 24, 31, 40, 44, 53,
  350.     10, 19, 23, 32, 39, 45, 52, 54,
  351.     20, 22, 33, 38, 46, 51, 55, 60,
  352.     21, 34, 37, 47, 50, 56, 59, 61,
  353.     35, 36, 48, 49, 57, 58, 62, 63
  354.     };
  355.   FILE * fp;
  356.   int tblno, i;
  357.   long val;
  358.   QUANT_TBL table;
  359.  
  360.   if ((fp = fopen(filename, "r")) == NULL) {
  361.     fprintf(stderr, "%s: can't open %s\n", progname, filename);
  362.     exit(EXIT_FAILURE);
  363.   }
  364.   tblno = 0;
  365.  
  366.   while ((val = read_qt_integer(fp)) != EOF) { /* read 1st element of table */
  367.     if (tblno >= NUM_QUANT_TBLS) {
  368.       fprintf(stderr, "%s: too many tables in file %s\n", progname, filename);
  369.       exit(EXIT_FAILURE);
  370.     }
  371.     table[0] = (QUANT_VAL) val;
  372.     for (i = 1; i < DCTSIZE2; i++) {
  373.       if ((val = read_qt_integer(fp)) == EOF) {
  374.     fprintf(stderr, "%s: incomplete table in file %s\n", progname, filename);
  375.     exit(EXIT_FAILURE);
  376.       }
  377.       table[ZIG[i]] = (QUANT_VAL) val;
  378.     }
  379.     j_add_quant_table(cinfo, tblno, table, scale_factor, FALSE);
  380.     tblno++;
  381.   }
  382.  
  383.   fclose(fp);
  384. }
  385.  
  386.  
  387. LOCAL void
  388. set_sample_factors (compress_info_ptr cinfo, char *arg)
  389. /* Process a sample-factors parameter string, of the form */
  390. /*     HxV[,HxV,...]    */
  391. {
  392. #define MAX_COMPONENTS 4    /* # of comp_info slots made by jcdeflts.c */
  393.   int ci, val1, val2;
  394.   char ch1, ch2;
  395.  
  396.   for (ci = 0; ci < MAX_COMPONENTS; ci++) {
  397.     if (*arg) {
  398.       ch2 = ',';        /* if not set by sscanf, will be ',' */
  399.       if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3)
  400.     usage();
  401.       if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',')
  402.     usage();        /* syntax check */
  403.       if (val1 <= 0 || val1 > 4 || val2 <= 0 || val2 > 4) {
  404.     fprintf(stderr, "JPEG sampling factors must be 1..4\n");
  405.     exit(EXIT_FAILURE);
  406.       }
  407.       cinfo->comp_info[ci].h_samp_factor = val1;
  408.       cinfo->comp_info[ci].v_samp_factor = val2;
  409.       while (*arg && *arg++ != ',') /* advance to next segment of arg string */
  410.     ;
  411.     } else {
  412.       /* reached end of parameter, set remaining components to 1x1 sampling */
  413.       cinfo->comp_info[ci].h_samp_factor = 1;
  414.       cinfo->comp_info[ci].v_samp_factor = 1;
  415.     }
  416.   }
  417. }
  418.  
  419.  
  420. LOCAL int
  421. parse_switches (compress_info_ptr cinfo, int last_file_arg_seen,
  422.         int argc, char **argv)
  423. /* Initialize cinfo with default switch settings, then parse option switches.
  424.  * Returns argv[] index of first file-name argument (== argc if none).
  425.  * Any file names with indexes <= last_file_arg_seen are ignored;
  426.  * they have presumably been processed in a previous iteration.
  427.  * (Pass 0 for last_file_arg_seen on the first or only iteration.)
  428.  */
  429. {
  430.   int argn;
  431.   char * arg;
  432.   char * qtablefile = NULL;    /* saves -qtables filename if any */
  433.   int q_scale_factor = 100;    /* default to no scaling for -qtables */
  434.  
  435.   /* (Re-)initialize the system-dependent error and memory managers. */
  436.   jselerror(cinfo->emethods);    /* error/trace message routines */
  437.   jselmemmgr(cinfo->emethods);    /* memory allocation routines */
  438.   cinfo->methods->c_ui_method_selection = c_ui_method_selection;
  439.  
  440.   /* Now OK to enable signal catcher. */
  441. #ifdef NEED_SIGNAL_CATCHER
  442.   emethods = cinfo->emethods;
  443. #endif
  444.  
  445.   /* Set up default JPEG parameters. */
  446.   /* Note that default -quality level here need not, and does not,
  447.    * match the default scaling for an explicit -qtables argument.
  448.    */
  449.   j_c_defaults(cinfo, 75, FALSE); /* default quality level = 75 */
  450.   is_targa = FALSE;
  451.  
  452.   /* Scan command line options, adjust parameters */
  453.  
  454.   for (argn = 1; argn < argc; argn++) {
  455.     arg = argv[argn];
  456.     if (*arg != '-') {
  457.       /* Not a switch, must be a file name argument */
  458.       if (argn <= last_file_arg_seen)
  459.     continue;        /* ignore it if previously processed */
  460.       break;            /* else done parsing switches */
  461.     }
  462.     arg++;            /* advance past switch marker character */
  463.  
  464.     if (keymatch(arg, "arithmetic", 1)) {
  465.       /* Use arithmetic coding. */
  466. #ifdef C_ARITH_CODING_SUPPORTED
  467.       cinfo->arith_code = TRUE;
  468. #else
  469.       fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
  470.           progname);
  471.       exit(EXIT_FAILURE);
  472. #endif
  473.  
  474.     } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
  475.       /* Enable debug printouts. */
  476.       /* On first -d, print version identification */
  477.       if (last_file_arg_seen == 0 && cinfo->emethods->trace_level == 0)
  478.     fprintf(stderr, "Independent JPEG Group's CJPEG, version %s\n%s\n",
  479.         JVERSION, JCOPYRIGHT);
  480.       cinfo->emethods->trace_level++;
  481.  
  482.     } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) {
  483.       /* Force a monochrome JPEG file to be generated. */
  484.       j_monochrome_default(cinfo);
  485.  
  486.     } else if (keymatch(arg, "maxmemory", 1)) {
  487.       /* Maximum memory in Kb (or Mb with 'm'). */
  488.       long lval;
  489.       char ch = 'x';
  490.  
  491.       if (++argn >= argc)    /* advance to next argument */
  492.     usage();
  493.       if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
  494.     usage();
  495.       if (ch == 'm' || ch == 'M')
  496.     lval *= 1000L;
  497.       cinfo->emethods->max_memory_to_use = lval * 1000L;
  498.  
  499.     } else if (keymatch(arg, "nointerleave", 3)) {
  500.       /* Create noninterleaved file. */
  501. #ifdef C_MULTISCAN_FILES_SUPPORTED
  502.       cinfo->interleave = FALSE;
  503. #else
  504.       fprintf(stderr, "%s: sorry, multiple-scan support was not compiled\n",
  505.           progname);
  506.       exit(EXIT_FAILURE);
  507. #endif
  508.  
  509.     } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
  510.       /* Enable entropy parm optimization. */
  511. #ifdef ENTROPY_OPT_SUPPORTED
  512.       cinfo->optimize_coding = TRUE;
  513. #else
  514.       fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
  515.           progname);
  516.       exit(EXIT_FAILURE);
  517. #endif
  518.  
  519.     } else if (keymatch(arg, "quality", 1)) {
  520.       /* Quality factor (quantization table scaling factor). */
  521.       int val;
  522.  
  523.       if (++argn >= argc)    /* advance to next argument */
  524.     usage();
  525.       if (sscanf(argv[argn], "%d", &val) != 1)
  526.     usage();
  527.       /* Set quantization tables (will be overridden if -qtables also given).
  528.        * Note: we make force_baseline FALSE.
  529.        * This means non-baseline JPEG files can be created with low Q values.
  530.        * To ensure only baseline files are generated, pass TRUE instead.
  531.        */
  532.       j_set_quality(cinfo, val, FALSE);
  533.       /* Change scale factor in case -qtables is present. */
  534.       q_scale_factor = j_quality_scaling(val);
  535.  
  536.     } else if (keymatch(arg, "qtables", 2)) {
  537.       /* Quantization tables fetched from file. */
  538.       if (++argn >= argc)    /* advance to next argument */
  539.     usage();
  540.       qtablefile = argv[argn];
  541.       /* we postpone actually reading the file in case -quality comes later */
  542.  
  543.     } else if (keymatch(arg, "restart", 1)) {
  544.       /* Restart interval in MCU rows (or in MCUs with 'b'). */
  545.       long lval;
  546.       char ch = 'x';
  547.  
  548.       if (++argn >= argc)    /* advance to next argument */
  549.     usage();
  550.       if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
  551.     usage();
  552.       if (lval < 0 || lval > 65535L)
  553.     usage();
  554.       if (ch == 'b' || ch == 'B')
  555.     cinfo->restart_interval = (UINT16) lval;
  556.       else
  557.     cinfo->restart_in_rows = (int) lval;
  558.  
  559.     } else if (keymatch(arg, "sample", 2)) {
  560.       /* Set sampling factors. */
  561.       if (++argn >= argc)    /* advance to next argument */
  562.     usage();
  563.       set_sample_factors(cinfo, argv[argn]);
  564.  
  565.     } else if (keymatch(arg, "smooth", 2)) {
  566.       /* Set input smoothing factor. */
  567.       int val;
  568.  
  569.       if (++argn >= argc)    /* advance to next argument */
  570.     usage();
  571.       if (sscanf(argv[argn], "%d", &val) != 1)
  572.     usage();
  573.       if (val < 0 || val > 100)
  574.     usage();
  575.       cinfo->smoothing_factor = val;
  576.  
  577.     } else if (keymatch(arg, "targa", 1)) {
  578.       /* Input file is Targa format. */
  579.       is_targa = TRUE;
  580.  
  581.     } else {
  582.       usage();            /* bogus switch */
  583.     }
  584.   }
  585.  
  586.   /* Post-switch-scanning cleanup */
  587.  
  588.   if (qtablefile != NULL)    /* process -qtables if it was present */
  589.     read_quant_tables(cinfo, qtablefile, q_scale_factor);
  590.  
  591.   return argn;            /* return index of next arg (file name) */
  592. }
  593.  
  594.  
  595. /*
  596.  * The main program.
  597.  */
  598.  
  599. GLOBAL int
  600. main (int argc, char **argv)
  601. {
  602.   struct Compress_info_struct cinfo;
  603.   struct Compress_methods_struct c_methods;
  604.   struct External_methods_struct e_methods;
  605.   int file_index;
  606.  
  607.   /* On Mac, fetch a command line. */
  608. #ifdef THINK_C
  609.   argc = ccommand(&argv);
  610. #endif
  611.  
  612.   progname = argv[0];
  613.  
  614.   /* Set up links to method structures. */
  615.   cinfo.methods = &c_methods;
  616.   cinfo.emethods = &e_methods;
  617.  
  618.   /* Install, but don't yet enable signal catcher. */
  619. #ifdef NEED_SIGNAL_CATCHER
  620.   emethods = NULL;
  621.   signal(SIGINT, signal_catcher);
  622. #ifdef SIGTERM            /* not all systems have SIGTERM */
  623.   signal(SIGTERM, signal_catcher);
  624. #endif
  625. #endif
  626.  
  627.   /* Scan command line: set up compression parameters, input & output files. */
  628.  
  629.   file_index = parse_switches(&cinfo, 0, argc, argv);
  630.  
  631. #ifdef TWO_FILE_COMMANDLINE
  632.  
  633.   if (file_index != argc-2) {
  634.     fprintf(stderr, "%s: must name one input and one output file\n", progname);
  635.     usage();
  636.   }
  637.   if ((cinfo.input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
  638.     fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
  639.     exit(EXIT_FAILURE);
  640.   }
  641.   if ((cinfo.output_file = fopen(argv[file_index+1], WRITE_BINARY)) == NULL) {
  642.     fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index+1]);
  643.     exit(EXIT_FAILURE);
  644.   }
  645.  
  646. #else /* not TWO_FILE_COMMANDLINE -- use Unix style */
  647.  
  648.   cinfo.input_file = stdin;    /* default input file */
  649.   cinfo.output_file = stdout;    /* always the output file */
  650.  
  651. #ifdef USE_SETMODE        /* need to hack file mode? */
  652.   setmode(fileno(stdin), O_BINARY);
  653.   setmode(fileno(stdout), O_BINARY);
  654. #endif
  655.  
  656.   if (file_index < argc-1) {
  657.     fprintf(stderr, "%s: only one input file\n", progname);
  658.     usage();
  659.   }
  660.   if (file_index < argc) {
  661.     if ((cinfo.input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
  662.       fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
  663.       exit(EXIT_FAILURE);
  664.     }
  665.   }
  666.  
  667. #endif /* TWO_FILE_COMMANDLINE */
  668.  
  669.   /* Figure out the input file format, and set up to read it. */
  670.   select_file_type(&cinfo);
  671.  
  672. #ifdef PROGRESS_REPORT
  673.   /* Start up progress display, unless trace output is on */
  674.   if (e_methods.trace_level == 0)
  675.     c_methods.progress_monitor = progress_monitor;
  676. #endif
  677.  
  678.   /* Do it to it! */
  679.   jpeg_compress(&cinfo);
  680.  
  681. #ifdef PROGRESS_REPORT
  682.   /* Clear away progress display */
  683.   if (e_methods.trace_level == 0) {
  684.     fprintf(stderr, "\r                \r");
  685.     fflush(stderr);
  686.   }
  687. #endif
  688.  
  689.   /* All done. */
  690.   exit(EXIT_SUCCESS);
  691.   return 0;            /* suppress no-return-value warnings */
  692. }
  693.